package com.yqd.lesson.typedactor

import scala.concurrent.ExecutionContext.Implicits.global
import akka.actor.{ActorRef, ActorSystem, TypedActor, TypedProps}

import scala.concurrent.{Await, Future}
import scala.util.Success
import scala.util.Failure
import scala.concurrent.duration._

trait Squarer {
  def squareDontCare(i: Int): Unit //fire-forget

  def square(i: Int): Future[Int] //non-blocking(非阻塞) send-request-reply

  def squareNowPlease(i: Int): Option[Int] //blocking(阻塞) send-request-reply

  def squareNow(i: Int): Int //blocking(阻塞) send-request-reply

  @throws(classOf[Exception]) //declare it or you will get an UndeclaredThrowableException
  def squareTry(i: Int): Int //blocking send-request-reply with possible exception
}

class SquarerImpl(val name: String) extends Squarer {

  //TODO 如果你的有类型actor的实现类扩展了akka.actor.TypedActor.Receiver，所有非方法调用MethodCall的消息会被传给onReceive方法.
  //TODO 实现了这个目上前还不清楚如何调用
  //class SquarerImpl(val name: String) extends TypedActor.Receiver with Squarer {

  def this() = this("default")
  def squareDontCare(i: Int): Unit = i * i //Nobody cares :(

  def square(i: Int): Future[Int] = Future.successful(i * i)

  def squareNowPlease(i: Int): Option[Int] = Some(i * i)

  def squareNow(i: Int): Int = i * i

  def squareTry(i: Int): Int = throw new Exception("Catch me!")


  /**override def onReceive(message: Any, sender: ActorRef): Unit = {
    println(s"接收消息是：" + message)
  }**/
}


object demo extends App {
  val system: ActorSystem = ActorSystem("akka")

  val mySquarer: Squarer = TypedActor(system).typedActorOf(TypedProps[SquarerImpl]())

  //阻塞调用
  println("squareNow:" + mySquarer.squareNow(5));

  //单向消息发送
  println("squareDontCare:" + mySquarer.squareDontCare(10))

  //阻塞调用
  println("squareNowPlease:" + mySquarer.squareNowPlease(10))

  //非阻塞调用
  val fSquare = mySquarer.square(10);
  fSquare.onComplete{
    case Success(result) => println(s"非阻塞调用Future = $result")
    case Failure(e) => e.printStackTrace
  }

  println("Future block is:"+Await.result(fSquare, 1.second))

  //终止actor
  TypedActor(system).stop(mySquarer)

}
